package cn.tedu.erp.project.service.impl;

import cn.tedu.erp.project.ex.ServiceException;
import cn.tedu.erp.project.mapper.AdminDeptMapper;
import cn.tedu.erp.project.mapper.AdminMapper;
import cn.tedu.erp.project.pojo.dto.AdminAddNewDTO;
import cn.tedu.erp.project.pojo.dto.AdminLoginDTO;
import cn.tedu.erp.project.pojo.dto.AdminUpdateDTO;
import cn.tedu.erp.project.pojo.entity.Admin;
import cn.tedu.erp.project.pojo.entity.AdminDept;
import cn.tedu.erp.project.pojo.vo.AdminListVO;
import cn.tedu.erp.project.pojo.vo.AdminStandardVO;
import cn.tedu.erp.project.security.AdminDetails;
import cn.tedu.erp.project.service.IAdminService;
import cn.tedu.erp.project.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Slf4j
@Service
@Transactional
public class AdminServiceImpl implements IAdminService {
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private AdminDeptMapper adminDeptMapper;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Value("${erp.jwt.secret-key}")
    private String secretKey;
    @Value("${erp.jwt.duration-in-minute}")
    private Long durationInMinute;

    /**
     * 用户登录
     */
    @Override
    public String login(AdminLoginDTO adminLoginDTO) {
        log.debug("开始执行[用户登录]的业务,参数为:{}", adminLoginDTO);
        //接收表单的用户名和密码
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginDTO.getUsername(), adminLoginDTO.getPassword()
        );
        //获取登录后的验证结果
        //认证信息authenticateResult中的当事人principal
        // 是userDetailsService中的loadUserByusername方法返回的的结果userdetails
        Authentication authenticateResult =
                authenticationManager.authenticate(authentication);
        log.debug("认证通过!(如果未通过,过程中将抛出异常,你不会看到此日志)");
        log.debug("认证结果:{}", authenticateResult);
        log.debug("认证结果中的当事人:{}", authenticateResult.getPrincipal());
        //将返回的认证信息保存到securityContext中
        //静态方法getContext()方法来获取当前的SecurityContext对象
        //静态方法clearContext()方法来清空SecurityContext中的信息
        //使用jwt机制后,登录成功后不需要再将认证信息存入到securityContext中
//        SecurityContext securityContext = SecurityContextHolder.getContext();
//        securityContext.setAuthentication(authenticateResult);

        //获取认证结果中当事人,得到当事人的信息(用户名,密码等等)
        AdminDetails adminDetails = (AdminDetails) authenticateResult.getPrincipal();
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", adminDetails.getId());//id
        claims.put("username", adminDetails.getUsername());//用户名
        //通过添加fastjson依赖,将权限列表转换为json格式的字符串
        String authoritiesJsonString = JSON.toJSONString(adminDetails.getAuthorities());
        claims.put("authoritiesJsonString", authoritiesJsonString);//权限列表

        //生成jwt
        String jwt = Jwts.builder()
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000))
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        log.debug("生成了jwt数据:{}", jwt);
        //返回jwt到控制器
        return jwt;
    }

    /**
     * 添加用户
     *
     * @param adminAddNewDTO
     */
    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        //通过参数得到部门id的数组
        Long[] deptIDs = adminAddNewDTO.getDeptIds();
        for (Long deptId : deptIDs) {
            if (deptId == 1) {
                //是:抛出异常
                String message = "添加失败,用户用户名已存在!";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
            }
        }
        //从参数对象中获取用户的名称
        String username = adminAddNewDTO.getUsername();
        //调用adminMapper的countbyusername()执行统计
        int countName = adminMapper.countByUsername(username);
        //判断统计结果是否大于0
        if (countName > 0) {
            //是:抛出异常
            String message = "添加失败,添加的用户用户名已存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
        }
        //检查手机号是否被占用
        String phone = adminAddNewDTO.getPhone();
        int countPhone = adminMapper.countByPhone(phone);
        if (countPhone > 0) {
            //是:抛出异常
            String message = "添加失败,添加的用户手机号已存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
        }
        //检查邮箱是否被占用
        String email = adminAddNewDTO.getPhone();
        int countEmail = adminMapper.countByPhone(email);
        if (countEmail > 0) {
            //是:抛出异常
            String message = "添加失败,添加的用户邮箱已存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
        }
        //创建对象
        Admin admin = new Admin();
        //复制属性
        BeanUtils.copyProperties(adminAddNewDTO, admin);
        //补全属性
        admin.setLoginCount(0);
        // 取出原密码 执行加密 再将密文存入到admin对象中
        String rawPassWord = admin.getPassword();
        String encodePassWord = passwordEncoder.encode(rawPassWord);
        admin.setPassword(encodePassWord);
        //调用adminMapper的insert方法
        int row = adminMapper.insert(admin);
        if (row != 1) {
            String message = "添加用户失败,服务器忙,稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT, message);
        }
        //为新添加的用户分配部门
        //基于部门id的数组创建adminMapper的批量插入用户的参数list<AdminDept>
        List<AdminDept> adminDeptList = new ArrayList<>();
        for (Long deptId : deptIDs) {
            AdminDept adminDept = new AdminDept();//创建用户部门对象
            adminDept.setAdminId(admin.getId());//添加要绑定对应部门的用户id
            adminDept.setDeptId(deptId);//添加部门id
            adminDeptList.add(adminDept);//将用户角色对象添加到数组中
        }
        //调用adminDeptMapper的insertBatch()执行插入
        row = adminDeptMapper.insertBatch(adminDeptList);
        if (row < 1) {
            String message = "添加用户失败,服务器忙,稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_INSERT, message);
        }
    }

    /**
     * 根据id删除用户
     *
     * @param id
     */
    @Override
    public void deleteById(Long id) {
        if (id == 1) {
            String message = "删除失败,被删除的用户不存在!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        //查询被删除的对象是否存在,否:报异常
        AdminStandardVO adminStandardVO = adminMapper.getStandardById(id);
        if (adminStandardVO == null) {
            String message = "删除失败,被删除的用户不存在!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        //调用adminMapper的delete方法
        int row = adminMapper.deleteById(id);
        if (row != 1) {
            String message = "删除失败,服务器忙,稍后再试!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_DELETE, message);
        }
        //调用adminDeptMapper的delete方法
        row = adminDeptMapper.deleteByAdminId(id);
        if (row < 1) {
            String message = "删除失败,服务器忙,稍后再试!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_DELETE, message);
        }
    }

    /**
     * 根据id修改用户
     *
     * @param id
     * @param adminUpdateDTO
     */
    @Override
    public void updateById(Long id, AdminUpdateDTO adminUpdateDTO) {
        if (id == 1) {
            String message = "修改失败,被修改的用户不存在!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        /*调用mapper的查询方法,判断查询结果是否为null,是则抛异常,
        创建Admin对象,复制属性,设置id,调用mapper的update方法修改*/
        log.debug("开始处理修改用户的业务,参数为id={},修改前的数据={}", id, adminUpdateDTO);
        //查询要修改的对象是否存在
        AdminStandardVO adminStandardVO = adminMapper.getStandardById(id);
        if (adminStandardVO == null) {
            String message = "修改失败,用户数据对象不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        log.debug("根据id={}获取的名称是否存在,结果为{}", id, adminStandardVO.getUsername());
        //查询要修改的用户名称是否同名
        int count = adminMapper.countByNameAndNotId(id, adminUpdateDTO.getUsername());
        if (count > 0) {
            String message = "修改失败,用户名称已经被占用";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
        }
        Admin admin = new Admin();
        //复制属性
        BeanUtils.copyProperties(adminUpdateDTO, admin);
        //设置id
        admin.setId(id);
        int rows = adminMapper.update(admin);
        if (rows != 1) {
            String message = "修改用户失败,服务器忙,请稍后再试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UPDATE, message);
        }
    }

    /**
     * 根据id查询用户详情
     *
     * @param id
     * @return
     */
    @Override
    public AdminStandardVO getStandardById(Long id) {
        if (id == 1) {
            String message = "查询失败,被查询的用户不存在!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        //调用adminMapper的getstandardvo方法
        AdminStandardVO adminStandardVO = adminMapper.getStandardById(id);
        if (adminStandardVO == null) {
            String message = "查询失败,被查询的用户不存在!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        return adminStandardVO;
    }


    /**
     * 根据昵称查询用户详情
     *
     * @param nickname
     * @return adminStandardVO
     */
    @Override
    public AdminStandardVO getByNickname(String nickname) {
        AdminStandardVO adminStandardVO = adminMapper.getByNickname(nickname);
        log.debug("查询到的结果为,{}",adminStandardVO);
        return adminStandardVO;
    }

    private void updateEnableById(Long id, Integer enable) {
        //调用mapper的查找id方法,查询被修改对象的id
        AdminStandardVO adminStandardVO = adminMapper.getStandardById(id);
        //判断被修改的对象是否为null,是就抛出异常
        if (adminStandardVO == null) {
            String message = ENABLE_TEXT[enable] + "失败,用户id不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        //判断查询结果中的enable与参数enable是否相同,如果是,则抛出异常(当前状态与目标状态相同,没必要执行更新)
        if (adminStandardVO.getEnable() == enable) {
            String message = ENABLE_TEXT[enable] + "失败,当前状态已经是"
                    + ENABLE_TEXT[enable] + "状态";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
        }
        //创建Admin对象
        Admin admin = new Admin();
        //向admin对象中封装属性值,id,enable,来自方法参数
        admin.setEnable(enable);
        admin.setId(id);
        //调用mapper对象的update()方法执行更新
        int row = adminMapper.update(admin);
        if (row != 1) {
            String message = ENABLE_TEXT[enable] + "类别失败,服务器忙,请稍后再试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UPDATE, message);
        }
    }

    /**
     * 根据id禁用用户
     *
     * @param id
     */
    @Override
    public void setEnable(Long id) {
        if (id == 1) {
            String message = "启用失败,被启用的用户不存在!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        updateEnableById(id, 1);
    }

    /**
     * 根据id禁用用户
     *
     * @param id
     */
    @Override
    public void setDisable(Long id) {
        if (id == 1) {
            String message = "启用失败,被启用的用户不存在!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        updateEnableById(id, 0);
    }

    private void updateManagerById(Long id, Integer manager) {
        //调用mapper的查找id方法,查询被修改对象的id
        AdminStandardVO adminStandardVO = adminMapper.getStandardById(id);
        //判断被修改的对象是否为null,是就抛出异常
        if (adminStandardVO == null) {
            String message = MANAGER_TEXT[manager] + "失败,用户id不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        //判断查询结果中的manager与参数manager是否相同,如果是,则抛出异常(当前状态与目标状态相同,没必要执行更新)
        if (adminStandardVO.getManager() == manager) {
            String message = MANAGER_TEXT[manager] + "失败,当前状态已经是"
                    + MANAGER_TEXT[manager] + "状态";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_CONFLICT, message);
        }
        //创建Admin对象
        Admin admin = new Admin();
        //向admin对象中封装属性值,id,manager,来自方法参数
        admin.setManager(manager);
        admin.setId(id);
        //调用mapper对象的update()方法执行更新
        int row = adminMapper.update(admin);
        if (row != 1) {
            String message = MANAGER_TEXT[manager] + "类别失败,服务器忙,请稍后再试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERROR_UPDATE, message);
        }
    }

    /**
     * 根据id启用用户为经理
     *
     * @param id
     */
    @Override
    public void setManager(Long id) {
        if (id == 1) {
            String message = "部门经理启用失败,被启用的用户不存在!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        updateManagerById(id, 1);
    }

    /**
     * 根据id禁用用户为经理
     *
     * @param id
     */
    @Override
    public void setNoManager(Long id) {
        if (id == 1) {
            String message = "部门经理启用失败,被启用的用户不存在!";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, message);
        }
        updateManagerById(id, 0);
    }

    /**
     * 查询用户列表
     *
     * @return
     */
    @Override
    public List<AdminListVO> list() {
        log.debug("开始处理[查询用户列表]的业务,无参数");
        //调用adminMapper的list方法
        List<AdminListVO> list = adminMapper.list();
        //使用list的迭代器
        Iterator<AdminListVO> iterator = list.iterator();
        //查询为1的对象,直到将该对象从list集合中删除
        while (iterator.hasNext()) {
            AdminListVO item = iterator.next();
            if (item.getId() == 1) {
                iterator.remove();
                break;
            }
        }
        return list;
    }

}
